/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.sc.senai.model.dao;

import br.sc.senai.model.exception.DAOExcption;
import br.sc.senai.model.util.Sup;
import br.sc.senai.model.util.LogUtil;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.SQLGrammarException;

/**
 *
 * @author Administrador
 */
public class Persist <T> {
    
    protected static Session session;
    private static final String nomeClasse = "Persist";

    public Persist() {
        openSession();
    }
    
    public void openSession() {
        try {
            session = DataBaseSession.openSession();
        } catch (Exception e) {
            LogUtil.addError("PersistDAO", "Falha ao abrir sessão.", true, e);
        }
    }
    
    public void closeSession() {
        try {
            DataBaseSession.closeSession();
        } catch (Exception e) {
            LogUtil.addError("PersistDAO", "Falha ao abrir sessão.", true, e);
        }
    }
    
    /**
     * Adiciona um novo registro no banco
     * @param pObject
     * @throws DAOExcption 
     */
    public T add(T pObject) throws DAOExcption {
        Transaction mTransaction = null;
        try {
            mTransaction = session.beginTransaction();
            session.save(pObject);
            
            LogUtil.addInfo(nomeClasse, "--------------- Add object --------------", Boolean.FALSE);
            LogUtil.addInfo(nomeClasse, String.format("Adicionado objeto : %s", pObject.getClass().getSimpleName()), Boolean.FALSE);
            
            return pObject;
        } catch (SQLGrammarException e) {
            mTransaction.rollback();
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_ADICIONAR.getValue() + " Exception : SQLGrammarException", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_ADICIONAR.getValue());
        } catch (ConstraintViolationException e) {
            mTransaction.rollback();
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_ADICIONAR.getValue() + " Não existe alguma referência no banco.", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_ADICIONAR.getValue());
        } catch (Exception e) {
            mTransaction.rollback();
            LogUtil.addError("", Sup.mensagens.ERRO_ADICIONAR.getValue(), false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_ADICIONAR.getValue());
        } finally{
            if (mTransaction == null || mTransaction.isActive())
                mTransaction.commit();
        }
    }
    
    /**
     * Deleta um registro no banco
     * Para deletar um objeto não basta apenas ter o atributo id preenchido,
     *deve-se carregar o objeto do banco utilizando o méto get ou load
     * @param pObject
     * @throws DAOExcption 
     */
    public Boolean delete(T pObject) throws DAOExcption {
        Transaction mTransaction = null;
        try {
            mTransaction = session.beginTransaction();
            session.delete(pObject);
            
            LogUtil.addInfo(nomeClasse, "--------------- Delete object --------------", Boolean.FALSE);
            LogUtil.addInfo(nomeClasse, String.format("Adicionado objeto : %s", pObject.getClass().getSimpleName()), Boolean.FALSE);
            
            return true;
        } catch (SQLGrammarException e) {
            mTransaction.rollback();
            LogUtil.addError(nomeClasse,Sup.mensagens.ERRO_DELETAR.getValue() + " Exception : SQLGrammarException", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_DELETAR.getValue());
        } catch (ConstraintViolationException e) {
            mTransaction.rollback();
            LogUtil.addError(nomeClasse,Sup.mensagens.ERRO_DELETAR.getValue() + " Verifique as referência do registro", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_DELETAR.getValue());
        } catch (Exception e) {
            mTransaction.rollback();
            LogUtil.addError("", Sup.mensagens.ERRO_DELETAR.getValue(), false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_DELETAR.getValue());
        } finally{
            if (mTransaction == null || mTransaction.isActive())
                mTransaction.commit();
        }
    }
    
    /**
     * Altera um registro no banco
     * Para alterar o objeto do banco deve-se primeiro carregar o objet
     * utilizando o método get ou load
     * @param pObject
     * @throws DAOExcption 
     */
    public T update(T pObject) throws DAOExcption {
        Transaction mTransaction = null;
        try {
            mTransaction = session.beginTransaction();
            session.update(pObject);
            
            LogUtil.addInfo(nomeClasse, "--------------- Alterar object --------------", Boolean.FALSE);
            LogUtil.addInfo(nomeClasse, String.format("Adicionado objeto : %s", pObject.getClass().getSimpleName()), Boolean.FALSE);
            
            return pObject;
        } catch (SQLGrammarException e) {
            mTransaction.rollback();
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_ALTERAR.getValue() + " Exception : SQLGrammarException", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_ALTERAR.getValue());
        } catch (ConstraintViolationException e) {
            mTransaction.rollback();
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_ALTERAR.getValue() + " Não existe alguma referência no banco.", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_ALTERAR.getValue());
        } catch (Exception e) {
            mTransaction.rollback();
            LogUtil.addError("", Sup.mensagens.ERRO_ALTERAR.getValue(), false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_ALTERAR.getValue());
        } finally{
            if (mTransaction == null || mTransaction.isActive())
                mTransaction.commit();
        }
    }
    
    /**
     * Pega um objeto pela PK's
     * @param pObject
     * @return
     * Retorna um objeto apartir do id (pk) do banco.
     * @throws DAOExcption 
     */
    public T getById(T pObject) throws DAOExcption {
        try {
            return (T) session.get(pObject.getClass(), pObject.hashCode());
        } catch (SQLGrammarException e) {
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_CONSULTAR.getValue() + " Exception : SQLGrammarException", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } catch (ConstraintViolationException e) {
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_CONSULTAR.getValue() + " Não existe alguma referência no banco.", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } catch (Exception e) {
            LogUtil.addError("", Sup.mensagens.ERRO_CONSULTAR.getValue(), false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } 
    }
    
    /***
     * Realiza consulta com sql enviado por parâmetro
     * @param pHql
     *  Exemplo da sintaxe do Hql:
     *  From Marca m Where m.nome = 'wolks'
     *  From Locacao o Where o.id = 1
     * 
     * Obs: Repare que o nome da tabela está sempre com a primeira letra 
     * em caixa alta, logo após o nome da tabela deve vir apelido/parâmetro
     * @return
     * @throws DAOExcption 
     */
    public List<T> loadByHql(String pHql) throws DAOExcption {
        try {
            return session.createQuery(pHql).list();
        } catch (SQLGrammarException e) {
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_CONSULTAR.getValue() + " Exception : SQLGrammarException", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } catch (ConstraintViolationException e) {
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_CONSULTAR.getValue() + " Não existe alguma referência no banco.", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } catch (Exception e) {
            LogUtil.addError("", Sup.mensagens.ERRO_CONSULTAR.getValue(), false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } 
    }
    
    /**
     * 
     * @param pSql
     * @return
     * @throws DAOExcption 
     */
    public List<T> loadAll(Class pClass) throws DAOExcption {
        try {
            return loadByHql(String.format("From %s p", pClass.getSimpleName()));
        } catch (SQLGrammarException e) {
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_CONSULTAR.getValue() + " Exception : SQLGrammarException", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } catch (ConstraintViolationException e) {
            LogUtil.addError(nomeClasse, Sup.mensagens.ERRO_CONSULTAR.getValue() + " Não existe alguma referência no banco.", false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } catch (Exception e) {
            LogUtil.addError("", Sup.mensagens.ERRO_CONSULTAR.getValue(), false, e);
            throw new DAOExcption(Sup.mensagens.ERRO_CONSULTAR.getValue());
        } 
    }
    
}
